﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using Lari.Configuration;
using Lari.Framework.Exceptions;
using Lari.Services.Data;
using Lari.Services.ViewModel;

namespace Lari.DataAccess
{
    public static class MasterDataAccess
    {

        private static string CurrentUser
        {
            get
            {
                if (HttpContext.Current != null && HttpContext.Current.User.Identity.IsAuthenticated)
                    return HttpContext.Current.User.Identity.Name;

                return null;
            }
        }

        #region Genders
        public static List<Gender> Genders(LariDbContext db)
        {
            return db.Genders.AsNoTracking().ToList();
        }

        public static Gender Genders(string genderCode, LariDbContext db)
        {
            //return db.Genders.FirstOrDefault(g => g.Code == genderCode);
            return db.Genders.Find(genderCode);
        }

        public static void Update(GenderModel model, LariDbContext db)
        {
            if (db.Genders.Any(g => g.Code != model.Code.Trim() && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            var gender = db.Genders.FirstOrDefault(g => g.Code == model.Code.Trim());

            if (gender == null) return;
            if (model.IsDefault)
            {
                db.Genders.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            gender.Name = model.Name.Trim();
            gender.IsDefault = model.IsDefault;
            gender.UpdatedBy = CurrentUser;
            gender.UpdatedOn = DateTime.Now;
            db.Entry(gender).State = EntityState.Modified;

            db.SaveChanges();
        }

        public static void Save(GenderModel model, LariDbContext db)
        {
            if (db.Genders.Any(g => g.Code == model.Code.Trim() || g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            if (model.IsDefault)
            {
                db.Genders.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            var gender = model.ConvertToEntityModel();
            gender.CreatedBy = CurrentUser;
            gender.CreatedOn = DateTime.Now;

            db.Entry(gender).State = EntityState.Added;
            db.SaveChanges();
        }
        #endregion

        #region country
        public static List<Country> Countries(LariDbContext db)
        {
            return db.Countries.ToList();
        }

        public static Country Country(LariDbContext db, string code)
        {
            return db.Countries.FirstOrDefault(c => c.Code == code);
        }

        public static void Update(LariDbContext db, CountryModal model)
        {
            if (db.Countries.Any(g => g.Code != model.Code.Trim() && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            var country = db.Countries.FirstOrDefault(g => g.Code == model.Code.Trim());

            if (country == null) return;
            if (model.IsDefault)
            {
                db.Countries.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            country.Name = model.Name.Trim();
            country.IsDefault = model.IsDefault;
            country.UpdatedBy = CurrentUser;
            country.UpdatedOn = DateTime.Now;
            db.Entry(country).State = EntityState.Modified;

            db.SaveChanges();
        }

        public static void Save(LariDbContext db, CountryModal model)
        {
            if (db.Countries.Any(g => g.Code == model.Code.Trim() || g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            if (model.IsDefault)
            {
                db.Countries.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            var country = model.ConvertToEntityModel();
            country.CreatedBy = CurrentUser;
            country.CreatedOn = DateTime.Now;

            db.Entry(country).State = EntityState.Added;
            db.SaveChanges();
        }

        #endregion

        #region states
        public static List<State> States(LariDbContext db)
        {
            return db.States.ToList();
        }

        public static State State(LariDbContext db, string code)
        {
            return db.States.FirstOrDefault(s => s.Code == code);
        }

        public static void Update(LariDbContext db, StateModel model)
        {
            if (db.States.Any(g => g.Code != model.Code.Trim() && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            var state = db.States.FirstOrDefault(g => g.Code == model.Code.Trim());

            if (state == null) return;
            if (model.IsDefault)
            {
                db.States.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            state.Name = model.Name.Trim();
            state.IsDefault = model.IsDefault;
            state.UpdatedBy = CurrentUser;
            state.UpdatedOn = DateTime.Now;
            db.Entry(state).State = EntityState.Modified;

            db.SaveChanges();
        }

        public static void Save(LariDbContext db, StateModel model)
        {
            if (db.States.Any(g => g.Code == model.Code.Trim() || g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            if (model.IsDefault)
            {
                db.States.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            var state = model.ConvertToEntityModel();
            state.CreatedBy = CurrentUser;
            state.CreatedOn = DateTime.Now;

            db.Entry(state).State = EntityState.Added;
            db.SaveChanges();
        }
        #endregion

        #region religions
        public static List<Religion> Rligions(LariDbContext db)
        {
            return db.Religions.ToList();
        }

        public static Religion Religion(LariDbContext db, string code)
        {
            return db.Religions.FirstOrDefault(r => r.Code == code);
        }

        public static void Update(ReligionModel model, LariDbContext db)
        {
            if (db.Religions.Any(g => g.Code != model.Code.Trim() && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            var religion = db.Religions.FirstOrDefault(g => g.Code == model.Code.Trim());

            if (religion == null) return;
            if (model.IsDefault)
            {
                db.Religions.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            religion.Name = model.Name.Trim();
            religion.IsDefault = model.IsDefault;
            religion.UpdatedBy = CurrentUser;
            religion.UpdatedOn = DateTime.Now;
            db.Entry(religion).State = EntityState.Modified;

            db.SaveChanges();
        }

        public static void Save(ReligionModel model, LariDbContext db)
        {
            if (db.Religions.Any(g => g.Code == model.Code.Trim() || g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            if (model.IsDefault)
            {
                db.Religions.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            var religion = model.ConvertToEntityModel();
            religion.CreatedBy = CurrentUser;
            religion.CreatedOn = DateTime.Now;

            db.Entry(religion).State = EntityState.Added;
            db.SaveChanges();
        }
        #endregion

        #region marital status
        public static List<MaritalStatus> MaritalStatuses(LariDbContext db)
        {
            return db.MaritalStatuses.ToList();
        }

        public static MaritalStatus MaritalStatus(LariDbContext db, string id)
        {
            return db.MaritalStatuses.FirstOrDefault(m => m.Code == id);
        }

        public static void Update(LariDbContext db, MaritalStatusModel model)
        {
            if (db.MaritalStatuses.Any(g => g.Code != model.Code.Trim() && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            var maritalStatuses = db.MaritalStatuses.FirstOrDefault(g => g.Code == model.Code.Trim());

            if (maritalStatuses == null) return;
            if (model.IsDefault)
            {
                db.MaritalStatuses.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            maritalStatuses.Name = model.Name.Trim();
            maritalStatuses.IsDefault = model.IsDefault;
            maritalStatuses.UpdatedBy = CurrentUser;
            maritalStatuses.UpdatedOn = DateTime.Now;
            db.Entry(maritalStatuses).State = EntityState.Modified;

            db.SaveChanges();
        }

        public static void Save(LariDbContext db, MaritalStatusModel model)
        {
            if (db.MaritalStatuses.Any(g => g.Code == model.Code.Trim() || g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateCodeName);

            if (model.IsDefault)
            {
                db.MaritalStatuses.Where(g => g.IsDefault).ToList().ForEach(m =>
                {
                    m.IsDefault = false;
                    db.Entry(m).State = EntityState.Modified;
                });
            }
            var maritalStatuses = model.ConvertToEntityModel();
            maritalStatuses.CreatedBy = CurrentUser;
            maritalStatuses.CreatedOn = DateTime.Now;

            db.Entry(maritalStatuses).State = EntityState.Added;
            db.SaveChanges();
        }

        #endregion

        #region employee type
        public static List<EmployeeType> EmployeeTypes(LariDbContext db)
        {
            return db.EmployeeTypes.ToList();
        }

        public static void Update(LariDbContext db, EmployeeTypeModel model)
        {
            if (db.EmployeeTypes.Any(g => g.ID != model.Id && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);

            var employeeType = db.EmployeeTypes.FirstOrDefault(g => g.ID == model.Id);
            if (employeeType == null) return;

            employeeType.Name = model.Name.Trim();
            employeeType.UpdatedBy = CurrentUser;
            employeeType.UpdatedOn = DateTime.Now;

            db.Entry(employeeType).State = EntityState.Modified;
            db.SaveChanges();
        }

        public static void Save(LariDbContext db, EmployeeTypeModel model)
        {
            if (db.EmployeeTypes.Any(g => g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);


            var employeeType = model.ConvertToEntityModel();
            employeeType.CreatedBy = CurrentUser;
            employeeType.CreatedOn = DateTime.Now;

            db.Entry(employeeType).State = EntityState.Added;
            db.SaveChanges();
        }
        public static EmployeeType EmployeeType(int id, LariDbContext db)
        {
            return db.EmployeeTypes.Find(id);
        }

        #endregion

        #region titles
        public static List<Title> Titles(LariDbContext db)
        {
            return db.Titles.ToList();
        }

        public static void Update(LariDbContext db, TitleModel model)
        {
            if (db.Titles.Any(g => g.ID != model.ID && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);

            var title = db.Titles.FirstOrDefault(g => g.ID == model.ID);
            if (title == null) return;

            title.Name = model.Name.Trim();
            title.UpdatedBy = CurrentUser;
            title.UpdatedOn = DateTime.Now;

            db.Entry(title).State = EntityState.Modified;
            db.SaveChanges();
        }

        public static void Save(LariDbContext db, TitleModel model)
        {
            if (db.Titles.Any(g => g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);


            var title = model.ConvertToEntityModel();
            title.CreatedBy = CurrentUser;
            title.CreatedOn = DateTime.Now;

            db.Entry(title).State = EntityState.Added;
            db.SaveChanges();
        }
        public static Title Title(LariDbContext db, int id)
        {
            return db.Titles.Find(id);
        }

        #endregion

        #region blood group
        public static List<Bloodgroup> Bloodgroups(LariDbContext db)
        {
            return db.Bloodgroups.ToList();
        }

        public static void Update(LariDbContext db, BloodgroupModel model)
        {
            if (db.Bloodgroups.Any(g => g.Id != model.Id && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);

            var bloodgroup = db.Bloodgroups.FirstOrDefault(g => g.Id == model.Id);
            if (bloodgroup == null) return;

            bloodgroup.Name = model.Name.Trim();
            bloodgroup.UpdatedBy = CurrentUser;
            bloodgroup.UpdatedOn = DateTime.Now;

            db.Entry(bloodgroup).State = EntityState.Modified;
            db.SaveChanges();
        }

        public static void Save(LariDbContext db, BloodgroupModel model)
        {
            if (db.Bloodgroups.Any(g => g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);


            var bloodgroup = model.ConvertToEntityModel();
            bloodgroup.CreatedBy = CurrentUser;
            bloodgroup.CreatedOn = DateTime.Now;

            db.Entry(bloodgroup).State = EntityState.Added;
            db.SaveChanges();
        }

        public static Bloodgroup Bloodgroup(LariDbContext db, int id)
        {
            return db.Bloodgroups.Find(id);
        }

        #endregion

        #region designation
        public static List<Designation> Designations(LariDbContext db)
        {
            return db.Designations.ToList();
        }

        public static void Update(LariDbContext db, DesignationModel model)
        {
            if (db.Designations.Any(g => g.Id != model.Id && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);

            var designation = db.Designations.FirstOrDefault(g => g.Id == model.Id);
            if (designation == null) return;

            designation.Name = model.Name.Trim();
            designation.UpdatedBy = CurrentUser;
            designation.UpdatedOn = DateTime.Now;

            db.Entry(designation).State = EntityState.Modified;
            db.SaveChanges();
        }

        public static void Save(LariDbContext db, DesignationModel model)
        {
            if (db.Designations.Any(g => g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);


            var designation = model.ConvertToEntityModel();
            designation.CreatedBy = CurrentUser;
            designation.CreatedOn = DateTime.Now;

            db.Entry(designation).State = EntityState.Added;
            db.SaveChanges();
        }

        public static Designation Designation(int id, LariDbContext db)
        {
            return db.Designations.Find(id);
        }
        #endregion

        #region department & desingnatin mapping
        public static List<Department> Departments(LariDbContext db)
        {
            return db.Departments.Include("DepDesignationMappings").ToList();
        }

        public static Department Department(LariDbContext db, int id, bool fetchSpecialization = false)
        {
            return fetchSpecialization ? db.Departments.Include("Specializations").FirstOrDefault(x => x.Id == id) : db.Departments.Include("DepDesignationMappings.Designation").FirstOrDefault(x => x.Id == id);
        }

        public static void Update(LariDbContext db, DepartmentModel model)
        {
            if (db.Departments.Any(g => g.Id != model.Id && g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);

            var department = db.Departments.FirstOrDefault(g => g.Id == model.Id);
            if (department == null) return;

            department.Name = model.Name.Trim();
            department.UpdatedBy = CurrentUser;
            department.UpdatedOn = DateTime.Now;

            db.Entry(department).State = EntityState.Modified;
            db.SaveChanges();
        }

        public static void Save(LariDbContext db, DepartmentModel model)
        {
            if (db.Departments.Any(g => g.Name == model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);


            var department = model.ConvertToEntityModel();
            department.CreatedBy = CurrentUser;
            department.CreatedOn = DateTime.Now;

            db.Entry(department).State = EntityState.Added;
            db.SaveChanges();
        }

        public static void Save(LariDbContext db, DepartmentDesignationModel model)
        {
            var dep = db.Departments.Include("DepDesignationMappings").FirstOrDefault(m => m.Id == model.DepartmentId);
            if (dep != null)
            {
                db.DepDesignationMappings.Where(m => m.DepartmentID == dep.Id).ToList().ForEach(d =>
                {
                    db.Entry(d).State = EntityState.Deleted;
                });

                model.Designations.FindAll(d => d.IsMapped).ForEach(d =>
                {
                    db.Entry(new DepDesignationMapping { DepartmentID = model.DepartmentId, DesignationID = d.DesignationId }).State = EntityState.Added;
                });

                dep.UpdatedBy = CurrentUser;
                dep.UpdatedOn = DateTime.Now;

                db.Entry(dep).State = EntityState.Modified;
                db.SaveChanges();
            }

        }


        public static void RemoveDesignationMapping(LariDbContext db, int departmentId)
        {
            db.DepDesignationMappings.Where(map => map.DepartmentID == departmentId).ToList().ForEach(m =>
            {
                db.Entry(m).State = EntityState.Deleted;
            });
            db.SaveChanges();

        }


        public static void SaveSpecialization(LariDbContext db, int departmentId, string specialization)
        {
            if (db.Specializations.Any(s => s.DepartmentID == departmentId && s.Name == specialization.Trim()))
            {
                throw new LariException(MessageCode.Generic.DuplicateName);
            }
            var spc = new Specialization { DepartmentID = departmentId, Name = specialization };
            db.Entry(spc).State = EntityState.Added;
            db.SaveChanges();
        }



        public static Specialization Specilization(int specilizationId, LariDbContext db)
        {
            return db.Specializations.Include("Department").FirstOrDefault(s => s.ID == specilizationId);
        }

        public static void ModifySpcealization(int departmentid, int specializationId, string specializationName, LariDbContext db)
        {
            if (db.Specializations.Any(s => s.ID != specializationId && s.DepartmentID == departmentid && s.Name == specializationName.Trim()))
            {
                throw new LariException(MessageCode.Generic.DuplicateName);
            }
            var spc = db.Specializations.Find(specializationId);
            if (spc != null)
            {
                spc.Name = specializationName.Trim();
                db.Entry(spc).State = EntityState.Modified;
                db.SaveChanges();

            }
        }

        public static int SpecilizationDelete(int specializationId, LariDbContext db)
        {
            int retValue = 0;
            var spc = db.Specializations.Find(specializationId);
            if (spc != null)
            {
                retValue = spc.DepartmentID;
                db.Entry(spc).State = EntityState.Deleted;
                db.SaveChanges();
            }
            return retValue;

        }

        #endregion

        #region Qualifications
        public static List<Qualification> Qualifications(LariDbContext db, int currentPage, ref int totalPageCount)
        {
            var temp = db.Qualifications.OrderBy(q => q.Name);

            totalPageCount = (int)Math.Ceiling((double)temp.Count() / ApplicationConfig.RowPerPage);

            var result = temp.Skip((currentPage - 1) * ApplicationConfig.RowPerPage)
            .Take(ApplicationConfig.RowPerPage)
            .ToList();
            return result;
        }
       

        public static Qualification Qualification(LariDbContext db, int id)
        {
            return db.Qualifications.Find(id);
        }

        public static List<Qualification> QualificationsAll(LariDbContext db)
        {
            return db.Qualifications.ToList();
        }
        public static void Save(QualificationModel model,LariDbContext db)
        {
            if(db.Qualifications.Any(q=> q.Name== model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);
            
            var data = model.ConvertToEntityModel();
            if (!model.NotDegree)
                data.Parent = null;
            data.CreatedBy = CurrentUser;
            data.CreatedOn = DateTime.Now;
            db.Entry(data).State = EntityState.Added;
            db.SaveChanges();
        }
        public static void Update(QualificationModel model, LariDbContext db)
        {
            if(db.Qualifications.Any(s=> s.Id!= model.Id && s.Name==model.Name.Trim()))
                throw new LariException(MessageCode.Generic.DuplicateName);

            var qual = db.Qualifications.Find(model.Id);
            if (qual == null) return;
            // incase parent is modified ito child check that no child exist in the parent
            if (!qual.Parent.HasValue && model.NotDegree)
            {
                if (db.Qualifications.Any(s => s.Parent.Value == model.Id))
                    throw new LariException(MessageCode.Master.QualificationRemoveChildFromParent);
            }

            qual.Name = model.Name;
            qual.Parent = model.NotDegree ? model.Parent : null;

            db.Entry(qual).State = EntityState.Modified;

            db.SaveChanges();
        }

        #endregion
    }   
}



